package com.tom.architect02.p4.day38.simple7.proxy;

import android.view.View;

import com.tom.architect02.p4.day38.simple7.base.BasePresenter;
import com.tom.architect02.p4.day38.simple7.base.BaseView;
import com.tom.architect02.p4.day38.simple7.inject.InjectPresenter;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * Added by Tom on 2024/01/31.
 * IMvpProxy的实现类。
 */
public class MvpProxyImpl<V extends BaseView> implements IMvpProxy {
    private V mView; // 传递view进来。
    // 缓存起来Presenter
    private List<BasePresenter> mPresenters; // 一对多的 非主Presenter，缓存起来，统一detach。

    public MvpProxyImpl(V view) {
        // 判断view是否为空，判断是不是接口。
        this.mView = view;
        mPresenters = new ArrayList<>();
    }

    @Override
    public void bindAndCreatePresenter() {
        handleInjects();
    }

    // 处理 InjectPresenter 注入
    private void handleInjects() {
        // 2. 处理注入Presenter。有就注入，没有就不处理。通过反射(也可以通过Dagger来实现)
        // 解决一个View里面有多个Presenter的情况。
        Field[] fields = mView.getClass().getDeclaredFields();
        for (Field field : fields) {
            InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
            if (injectPresenter != null) {
                // 创建注入。
                Class<? extends BasePresenter> presentClazz = null;
                // 做类型的判断。可以获取继承的父类，如果不是继承BasePresenter，就抛异常处理。
//                try {
                // (Class<? extends BasePresenter>) 相当于 Class，编译器在运行的时候，会对泛型进行擦除。
                presentClazz = (Class<? extends BasePresenter>) field.getType(); // 泛型擦除
                if (!BasePresenter.class.isAssignableFrom(presentClazz)) {
                    // 判断这个Class 类，是否是继承自 BasePresenter，如果不是就抛异常。
                    // eg: TextView,添加注入标记。
                    throw new RuntimeException("不支持的inject presenter类型:" + presentClazz.getName());
                }
//                } catch (Exception e) {
//                    // 处理别的注入。 不会报错。
//                    throw new RuntimeException("不支持的注入类型，请注入InjectPresenter：" + field.getType().getName());
//                }
                BasePresenter basePresenter = null;
                try {
                    // 创建Presenter对象。通过反射new Presenter对象。
                    basePresenter = presentClazz.newInstance();
                    basePresenter.attach(mView); // 如何解决解绑。
                    mPresenters.add(basePresenter); // 缓存起来。
                    // 设置Presenter对象
                    field.setAccessible(true);
                    field.set(mView, basePresenter); // 给对象mPresenter1，mPresenter2 赋值。
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 检测 view层，是否实现了 BasePresenter的View的接口。
                checkView(basePresenter);
            }
        }
    }

    // Activity未实现 BaseView
    // $Proxy3 cannot be cast to ...**BaseView
    // 未实现接口：MainActivity3806 must implements com.tom.architect02.p4.day38.simple7.mvp.UserInfoContact$UserInfoView
    private void checkView(BasePresenter basePresenter) {
        // 1.拿到basePresenter的view 接口。
        Type[] params = ((ParameterizedType) basePresenter.getClass().getGenericSuperclass()).getActualTypeArguments();
        Class viewClazz = ((Class) params[0]);

        // 2.拿到view层的所有接口，
        Class[] viewClasses = mView.getClass().getInterfaces();
        // 3.View层没有实现，就抛异常。
        boolean isImplementView = false;
        for (Class viewClass : viewClasses) {
            if (viewClass.isAssignableFrom(viewClazz)) {
                // 已经实现了接口
                isImplementView = true;
            }
        }
        if (!isImplementView) { // 4.如果Activity 未实现接口。抛异常。
            throw new RuntimeException(mView.getClass().getSimpleName() + " must implements " + viewClazz.getName());
        }
    }


    @Override
    public void unbindPresenter() {
        mView = null;
        for (BasePresenter presenter : mPresenters) {
            presenter.detach(); // 解绑。
        }
    }

}
